// StreamObjects.h

#ifndef __STREAM_OBJECTS_H
#define __STREAM_OBJECTS_H

//#include "Common/Buffer.h"
#include "IStream.h"

#include <vector>

struct CReferenceBuf /*:
  public IUnknown*/
{
  //CByteBuffer Buf;  
	std::vector<unsigned char> Buf;
};

class ATL_NO_VTABLE CBufInStream:
  public IInStream,
  public CComObjectRootEx<CComSingleThreadModel>  
{
  const BYTE *_data;
  UINT64 _pos;
  size_t _size;
  //CComPtr<IUnknown> _ref;
public:
  void Init(const BYTE *data, size_t size)//, IUnknown *ref = 0)
  {
    _data = data;
    _size = size;
    _pos = 0;
  //  _ref = ref;
  }
  void Init(CReferenceBuf *ref) //{ Init(ref->Buf, ref->Buf.GetCapacity());} //, ref); }
  { 
	  ATLASSERT(ref->Buf.size());
	Init((const BYTE *)&ref->Buf[0], ref->Buf.size());
  } //, ref); }

  BEGIN_COM_MAP(CBufInStream)
	  COM_INTERFACE_ENTRY(IInStream)	  
  END_COM_MAP()



  DECLARE_PROTECT_FINAL_CONSTRUCT()

  HRESULT FinalConstruct()
  {
	  Init(NULL, 0);
	  return S_OK;
  }

  void FinalRelease()
  {

  }
  STDMETHOD(Read)(void *data, UINT32 size, UINT32 *processedSize);
  STDMETHOD(Seek)(INT64 offset, UINT32 seekOrigin, UINT64 *newPosition);
};

/*class CByteDynBuffer
{
  size_t _capacity;
  BYTE *_buf;
public:
  CByteDynBuffer(): _capacity(0), _buf(0) {};
  // there is no copy constructor. So don't copy this object.
  ~CByteDynBuffer() { Free(); }
  void Free();
  size_t GetCapacity() const { return  _capacity; }
  operator BYTE*() const { return _buf; };
  operator const BYTE*() const { return _buf; };
  bool EnsureCapacity(size_t capacity);
};*/

class ATL_NO_VTABLE CDynBufSeqOutStream:
  public ISequentialOutStream,
  public CComObjectRootEx<CComSingleThreadModel>
{
  //CByteDynBuffer _buffer;
	std::vector<BYTE> _buffer;
  size_t _size;
public:
  CDynBufSeqOutStream(): _size(0) {}
  void Init() { _size = 0;  }
  size_t GetSize() const { return _size; }
  const BYTE *GetBuffer() const 
  { 
	  if(!_buffer.size())
		  return NULL;
	  return &_buffer[0]; 
  }
  void CopyToBuffer(std::vector<unsigned char> &dest) const;
  BYTE *GetBufPtrForWriting(size_t addSize);
  void UpdateSize(size_t addSize) { _size += addSize; }
    
  BEGIN_COM_MAP(CDynBufSeqOutStream)
	  COM_INTERFACE_ENTRY(ISequentialOutStream)	  
  END_COM_MAP()



  DECLARE_PROTECT_FINAL_CONSTRUCT()

  HRESULT FinalConstruct()
  {
	  Init();
	  return S_OK;
  }

  void FinalRelease()
  {

  }

  STDMETHOD(Write)(const void *data, UINT32 size, UINT32 *processedSize);
};

class ATL_NO_VTABLE CBufPtrSeqOutStream:
  public ISequentialOutStream,
  public CComObjectRootEx<CComSingleThreadModel>
{
  BYTE *_buffer;
  size_t _size;
  size_t _pos;
public:
  void Init(BYTE *buffer, size_t size)
  {
    _buffer = buffer;
    _pos = 0;
    _size = size;
  }
  size_t GetPos() const { return _pos; }

  BEGIN_COM_MAP(CBufPtrSeqOutStream)
	  COM_INTERFACE_ENTRY(ISequentialOutStream)	  
  END_COM_MAP()



  DECLARE_PROTECT_FINAL_CONSTRUCT()

  HRESULT FinalConstruct()
  {
	  Init(NULL, 0);
	  return S_OK;
  }

  void FinalRelease()
  {

  }

  STDMETHOD(Write)(const void *data, UINT32 size, UINT32 *processedSize);
};

class ATL_NO_VTABLE CSequentialOutStreamSizeCount:
  public ISequentialOutStream,
  public CComObjectRootEx<CComSingleThreadModel>
{
  CComPtr<ISequentialOutStream> _stream;
  UINT64 _size;
public:
  void SetStream(ISequentialOutStream *stream) { _stream = stream; }
  void Init() { _size = 0; }
  UINT64 GetSize() const { return _size; }

  BEGIN_COM_MAP(CSequentialOutStreamSizeCount)
	  COM_INTERFACE_ENTRY(ISequentialOutStream)	  
  END_COM_MAP()



  DECLARE_PROTECT_FINAL_CONSTRUCT()

  HRESULT FinalConstruct()
  {
	  Init();
	  return S_OK;
  }

  void FinalRelease()
  {

  }
  STDMETHOD(Write)(const void *data, UINT32 size, UINT32 *processedSize);
};

class ATL_NO_VTABLE CCachedInStream :
  public IInStream,
  public CComObjectRootEx<CComSingleThreadModel>
{
  UINT64 *_tags;
  BYTE *_data;
  size_t _dataSize;
  unsigned _blockSizeLog;
  unsigned _numBlocksLog;
  UINT64 _size;
  UINT64 _pos;
protected:
  virtual HRESULT ReadBlock(UINT64 blockIndex, BYTE *dest, size_t blockSize) = 0;
public: 
  void Free();
  bool Alloc(unsigned blockSizeLog, unsigned numBlocksLog);
  void Init(UINT64 size);

  BEGIN_COM_MAP(CCachedInStream)
	  COM_INTERFACE_ENTRY(IInStream)		
  END_COM_MAP()



  DECLARE_PROTECT_FINAL_CONSTRUCT()

  HRESULT FinalConstruct()
  {
	  _tags = 0;
	  _data = 0;
	  return S_OK;
  }

  void FinalRelease()
  {
	  Free();
  }
  
  STDMETHOD(Read)(void *data, UINT32 size, UINT32 *processedSize);
  STDMETHOD(Seek)(INT64 offset, UINT32 seekOrigin, UINT64 *newPosition);
};

#endif
